package com.peach.controller.DeviceManage;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.notnoop.apns.APNS;
import com.notnoop.apns.ApnsService;
import com.peach.Application;
import com.peach.domain.DeviceManage.Device;
import com.peach.domain.DeviceManage.Message;
import com.peach.domain.DeviceManage.MyApp;
import com.peach.domain.ResultVO;
import com.peach.domain.UserManage.User;
import com.peach.service.DeviceManage.DeviceApplication;
import com.peach.service.DeviceManage.PushMsgApplication;
import com.peach.service.UserManage.UserApplication;
import com.peach.utils.DeviceUtil;
import com.peach.utils.JsonConfig;
import com.peach.utils.TokenConfig;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;


@Controller
@RequestMapping("/mdm")

public class MDMController {

    //发送指令之前修改此属性的值，即可发送不同指令
    public static String msg;

    //用以判断命令类型，若为还原出厂设置，则需要数据库的数据同步。
    public String recoverDevice = null;
    @Autowired
    private PushMsgApplication pushMsgApplication;

    @Autowired
    private DeviceApplication deviceApplication;

    @Autowired
    private UserApplication userApplication;

    //运行时要用到的两个参数，用以在设备响应指令的时候识别指令类型和当前是哪个设备
    private String currentCommand = "";
    private String currentUdid = "";


    // p12文件的本地路径
    public static String certPath = "src/main/resources/forServer.p12";
    //p12文件的密码
    public static String certPassword = "Wwhosyour123";

    @RequestMapping("/index")
    public String index() {
        return "forward:/index.html";
    }

    @RequestMapping(value = "/login",method = RequestMethod.PUT)
    public void doPut(HttpServletRequest req, HttpServletResponse res) throws IOException, DocumentException {
        SAXReader reader = new SAXReader();
        try {
            //dom4j根据标签值遍历响应数据
            Document doc = reader.read(req.getInputStream());
            Element root = doc.getRootElement();
            Element dict = root.element("dict");
            List<Element> strings = dict.elements("string");
            //下面几步可以获取完整的响应数据result
            StringWriter sw = new StringWriter();
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter xw = new XMLWriter(sw, format);
            xw.write(doc);
            String result = sw.toString();
            System.out.println(result);
            List<Element> apps = null;
            Element deviceDetail = null;
            for ( Iterator j = dict.elementIterator(); j.hasNext();) {
                Element key = (Element) j.next();
                System.out.println(key.getText());
                switch (key.getData().toString()){
                    case "Status"://如果Status的值为Idle即为设备准备好可以接受指令。
                        String status =((Element) j.next()).getData().toString();//Status的下一个子节点即为Status的值
                        if ("Idle".equals(status)){
                            res.setHeader("content-type", "application/xml;charset=UTF-8");
                            res.setCharacterEncoding("UTF-8");
                            String configTitle = "Mbaike_DeviceLock";
                            res.setHeader("Content-Disposition", "attachment; filename=" + configTitle + ".plist");
                            PrintWriter sos = res.getWriter();
                            sos.write(msg);
                            sos.flush();
                            sos.close();
                        }
                        break;
                    //TODO: 我也不知道获取这个来干嘛，反正这个可以判断当前响应的指令和设备的UDID
                    case "CommandUUID": //可以做设备实施指令之后的回调
                        String commandUUID =((Element) j.next()).getData().toString();

                        String[] commandAndUdid = commandUUID.split("-");
                        currentCommand = commandAndUdid[0];
                        if ("installApp".equals(currentCommand)) {

                        } else if ("removeApp".equals(currentCommand)) {

                        } else if ("queryInstalledApp".equals(currentCommand)) {
                            j.next();
                            Element array = (Element) j.next();
                            apps = array.elements("dict");//把应用列表存储到apps数组中
                        } else if ("deviceDetail".equals(currentCommand)) {
                            j.next();
                            deviceDetail = (Element) j.next();
                        } else if ("installApp".equals(currentCommand)) {

                        } else if ("erase".equals(currentCommand)){
                            deviceApplication.deleteDeviceWithUDID(new Device(commandAndUdid[1]));
                        }
                        break;
                    case "UDID":
                        currentUdid = ((Element) j.next()).getText();
                        break;
                    default:
                        break;
                }
            }

            if (apps != null){
                System.out.println(apps.size());
                //清除旧App
                int affRowCleanOldAppList = deviceApplication.cleanOldAppList(currentUdid);
                for (Element app: apps
                        ) {
                    MyApp myApp = new MyApp();
                    for (Iterator j = app.elementIterator(); j.hasNext();){
                        Element appDetail = (Element) j.next();
                        if ("Name".equals(appDetail.getData().toString())){
                            myApp.setAppName(((Element) j.next()).getData().toString());
                        }
                        if ("Identifier".equals(appDetail.getData().toString())){
                            myApp.setId(((Element) j.next()).getData().toString() + "-" + currentUdid);
                        }
                        myApp.setUdid(currentUdid);
                        myApp.setUpdateTime(new Date());
                    }
                    //持久化 myapp
                    int affRowInsertNewApp = deviceApplication.insertNewApp(myApp);
                }
            }

            if (deviceDetail != null){
                Device device = new Device();
                device.setUdid(currentUdid);
                for ( Iterator j = deviceDetail.elementIterator(); j.hasNext();) {
                    Element key = (Element) j.next();
                    if ("BatteryLevel".equals(key.getText())){
                        device.setBatteryLevel(((Element) j.next()).getText());
                    }
                    if ("CurrentCarrierNetwork".equals(key.getText())){
                        device.setCurrentCarrierNetwork(((Element) j.next()).getText());
                    }
                    if ("OSVersion".equals(key.getText())){
                        device.setOSVersion(((Element) j.next()).getText());
                    }
                    if ("PhoneNumber".equals(key.getText())){
                        device.setPhoneNumber(((Element) j.next()).getText());
                    }
                    if ("SerialNumber".equals(key.getText())){
                        device.setSerialNumber(((Element) j.next()).getText());
                    }
                    if ("DeviceName".equals(key.getText())){
                        device.setNickName(((Element) j.next()).getText());
                    }
                    if ("ProductName".equals(key.getText())){
                        device.setProductName(DeviceUtil.transferProductName(((Element) j.next()).getText()));
                    }
                    device.setUpdateTime(new Date());
                }
                //持久化 deviceDetail
                int affRowUpdateDevice = deviceApplication.updateDeviceDetail(device);

            }
        } catch (Exception e) {
        }
    }



    //发送指令的参数："udid"和"自定义指令类型，如'lock'"，然后就会修改MDM的静态成员变量msg指向的内容，将其改为锁屏指令。
    @RequestMapping("/push")
    @ResponseBody
    public ResultVO sendMsgToAPNS (HttpServletRequest req, HttpServletResponse res) throws IOException {

        String reqJson = null;
        try {
            reqJson = JsonConfig.getRequestPostStr(req);
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject json = JSON.parseObject(reqJson);

        String udid = json.getString("udid");
        String orderType = json.getString("orderType");
        ResultVO rvo = new ResultVO();
        StringBuffer pushResultMsg = new StringBuffer("发送指令结果：");
        //指令中文名，用以返还发送指令结果给前端
        String orderString = "";
        //再次校验前端传来的设备 是否存在在数据库中
        Device device = new Device();
        device.setUdid(udid);
        List<Device> devices = deviceApplication.selectDeviceWithUDID(device);
        //如果能找到对应udid的设备，即此设备已注册管理。准备进行指令发送
        if (devices.size() > 0){
            //再检验用户的合法性（用户有可能已经被冻结）
            //使用方法转换原始token Fix:token位数错误的问题
            String token = TokenConfig.parseToken(devices.get(0).getToken());
            String pushMagic = devices.get(0).getPushMagic();
            ApnsService service = APNS.newService().withCert(certPath,certPassword).withProductionDestination().build();
            //发指令同时改变指令的类型
            if (!"".equals(orderType)){
                switch (orderType){
                    case "lock":
                        //传入锁屏提示语
                        msg = pushMsgApplication.prepareDeviceLockPlist(udid);
                        orderString = "锁屏";
                        break;
                    case "recover":
                        String pin = json.getString("pin");
                        msg = pushMsgApplication.prepareErasePlist(pin,udid);
                        orderString = "还原出厂设置";
                        recoverDevice = udid;
                        break;
                    case "installApp":
                        String appId = json.getString("appId");
                        msg = pushMsgApplication.prepareInstallAppPlist(appId,udid);
                        orderString = "安装应用程序";
                        //测试appID:450748070  有道云笔记
                        break;
                    case "queryAllApp":
                        msg = pushMsgApplication.prepareQueryInstalledAppPlist(udid);
                        orderString = "查看所有应用程序";
                        break;
                    case "queryDeviceDetail":
                        msg = pushMsgApplication.prepareQueryPlist(udid);
                        orderString = "查看设备详情";
                        break;
                    case "lostMode"://todo:需要刷出手机监管模式，要升级系统
                        msg = pushMsgApplication.prepareLostModePlist(udid);
                        orderString = "开启丢失模式";
                        break;
                    case "removeApp"://todo:指令无效，不懂
                        String id = json.getString("identifier");
                        String identifier = id.split("-")[0];
                        msg = pushMsgApplication.prepareRemoveAppPlist(udid,identifier);
                        orderString = "卸载应用";
                        break;
                    case "cleanPasscode"://todo:unLockToken 格式不对，不知道他要什么格式
                        String unLockToken = devices.get(0).getUnLockToken();
                        msg = pushMsgApplication.prepareCleanPasscodePlist(udid,unLockToken);
                        orderString = "清除设备锁屏密码";
                        break;
                    default:
                        break;
                }
            }else {
                rvo.setSuccess(false);
                rvo.setMsg("请选择指令类型！");
                return rvo;
            }
            String payload = APNS.newPayload().customField("mdm",pushMagic).build();
            System.out.print("通知APNS服务器，让APNS服务器去唤醒名为<"+devices.get(0).getNickName()+">的设备");
            //发送通知到APNS
            service.push(token,payload);
            pushResultMsg.append("发送"+orderString+"指令到名为<"+devices.get(0).getNickName()+">的设备：成功！");
            rvo.setSuccess(true);
            rvo.setMsg(pushResultMsg.toString());
            return rvo;
        }else {
            pushResultMsg.append("发送"+orderString+"指令到名为<"+devices.get(0).getNickName()+">的设备：失败！该设备注册过程中出现了错误，请按要求安装配置文件，或联系管理员！");
            rvo.setSuccess(false);
            rvo.setMsg(pushResultMsg.toString());
            return rvo;
        }
    }

    @RequestMapping("/queryAllDevice")
    @ResponseBody
    public ResultVO queryAllDevice(HttpServletRequest req, HttpServletResponse res){
        String reqJson = null;
        try {
            reqJson = JsonConfig.getRequestPostStr(req);
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject json = JSON.parseObject(reqJson);
        String owner = json.getString("owner");
        Device device = new Device();
        device.setOwner(owner);
        List<Device> devices = deviceApplication.selectDeviceWithOwner(device);
        //调整数组中每个设备的电量格式
        for (Device d: devices
                ) {
            if (d.getBatteryLevel() != null){
                DecimalFormat df = new DecimalFormat("######0.00");//四舍五入保留两位小数
                double batteryLevelNum = Double.parseDouble(d.getBatteryLevel()) * 100;
                if (batteryLevelNum >= 0) {
                    d.setBatteryLevel((df.format(batteryLevelNum)) + "%");
                }else {//若电量为-1.0 则表示无法检测电量
                    d.setBatteryLevel("无法检测电量");
                }
            }else {//若电量为null 也表示无法检测电量
                d.setBatteryLevel("无法检测电量");
            }
        }
        ResultVO rvo = new ResultVO();
        if (devices.size()>0){
            rvo.setSuccess(true);
            rvo.setData(devices);
            rvo.setMsg("");
        }else {
            rvo.setSuccess(false);
            rvo.setData(new ArrayList<>());
            rvo.setMsg("您还未注册过设备");
        }
        return rvo;
    }

    @RequestMapping("/queryOneDevice")
    @ResponseBody
    public ResultVO queryOneDevice(HttpServletRequest req, HttpServletResponse res) {
        String reqJson = null;
        try {
            reqJson = JsonConfig.getRequestPostStr(req);
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject json = JSON.parseObject(reqJson);
        String udid = json.getString("udid");
        Device device = new Device();
        device.setUdid(udid);
        List<Device> devices = deviceApplication.selectDeviceWithUDID(device);
        ResultVO rvo = new ResultVO();
        if (devices.size() > 0) {
            device = devices.get(0);
            rvo.setSuccess(true);
            //电量转换
            if (device.getBatteryLevel() != null){
                DecimalFormat df = new DecimalFormat("######0.00");//四舍五入保留两位小数
                double batteryLevelNum = Double.parseDouble(device.getBatteryLevel()) * 100;
                if (batteryLevelNum >= 0) {
                    device.setBatteryLevel((df.format(batteryLevelNum)) + "%");
                }else {//若电量为-1.0 则表示无法检测电量
                    device.setBatteryLevel("无法检测电量");
                }
            }else {//若电量为null 也表示无法检测电量
                device.setBatteryLevel("无法检测电量");
            }
            rvo.setData(devices);
            rvo.setMsg("");
        } else {
            rvo.setSuccess(false);
            rvo.setMsg("找不到此设备");
        }
        return rvo;
    }

    @RequestMapping("/test")
    public ResultVO test(HttpServletRequest req, HttpServletResponse res) {
        return new ResultVO(true,null,"");
    }

}
